package com.bluedot.www.core.utils;

import com.bluedot.www.framework.mvc.servlet.http.MultipartFile;
import net.coobird.thumbnailator.Thumbnails;

import javax.imageio.ImageIO;
import java.awt.*;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import java.util.List;

/**
 * 图片处理类
 *
 * @author GUOZHIPENG
 * @version 1.0
 * @date 2021/8/7 17:34
 */
public class ImageUtil {


    /**
     * 灰度化，即把彩色图片灰度化便于后续对图片的处理
     *
     * @param bufferedImage 传入图片
     * @return java.awt.image.BufferedImage
     * @author GUOZHIPENG
     * @date 2021/8/7 17:35
     */
    public static BufferedImage grayImage(BufferedImage bufferedImage) {
        int width = bufferedImage.getWidth();
        int height = bufferedImage.getHeight();

        BufferedImage grayBufferedImage = new BufferedImage(width, height, bufferedImage.getType());
        for (int i = 0; i < bufferedImage.getWidth(); i++) {
            for (int j = 0; j < bufferedImage.getHeight(); j++) {
                final int color = bufferedImage.getRGB(i, j);
                final int r = (color >> 16) & 0xff;
                final int g = (color >> 8) & 0xff;
                final int b = color & 0xff;
                int gray = (int) (0.3 * r + 0.59 * g + 0.11 * b);
                int newPixel = colorToRGB(255, gray, gray, gray);
                grayBufferedImage.setRGB(i, j, newPixel);
            }
        }

        return grayBufferedImage;
    }

    /**
     * 二值化，即把灰度化图片经过二值化变成只有黑白(只有0,1的矩阵)的数据，便于后续对图片的处理
     *
     * @param image 原图片
     * @return java.awt.image.BufferedImage
     * @author GUOZHIPENG
     * @date 2021/8/15 10:49
     */
    public static BufferedImage binaryImageWithSW(BufferedImage image, int Sw) throws Exception {
        int w = image.getWidth();
        int h = image.getHeight();
        float[] rgb = new float[3];
        double[][] zuobiao = new double[w][h];
        int black = new Color(0, 0, 0).getRGB();
        int white = new Color(255, 255, 255).getRGB();
        BufferedImage bi = new BufferedImage(w, h,
                BufferedImage.TYPE_BYTE_BINARY);
        ;
        for (int x = 0; x < w; x++) {
            for (int y = 0; y < h; y++) {
                int pixel = image.getRGB(x, y);
                rgb[0] = (pixel & 0xff0000) >> 16;
                rgb[1] = (pixel & 0xff00) >> 8;
                rgb[2] = (pixel & 0xff);
                float avg = (rgb[0] + rgb[1] + rgb[2]) / 3;
                zuobiao[x][y] = avg;

            }
        }
        //这里是阈值，白底黑字还是黑底白字，大多数情况下建议白底黑字，后面都以白底黑字为例
        //192
        double SW = Sw;
        for (int x = 0; x < w; x++) {
            for (int y = 0; y < h; y++) {
                if (zuobiao[x][y] < SW) {
                    bi.setRGB(x, y, black);
                } else {
                    bi.setRGB(x, y, white);
                }
            }
        }
        return bi;
    }

    /**
     * 二值化，默认阀值
     *
     * @param image 原图片
     * @return java.awt.image.BufferedImage
     * @author GUOZHIPENG
     * @date 2021/8/15 10:49
     */
    public static BufferedImage binaryImage(BufferedImage image) throws Exception {
        return binaryImageWithSW(image, 115);
    }

    /**
     * 颜色分量转换为RGB值
     *
     * @param alpha
     * @param red
     * @param green
     * @param blue
     * @return
     */
    private static int colorToRGB(int alpha, int red, int green, int blue) {

        int newPixel = 0;
        newPixel += alpha;
        newPixel = newPixel << 8;
        newPixel += red;
        newPixel = newPixel << 8;
        newPixel += green;
        newPixel = newPixel << 8;
        newPixel += blue;

        return newPixel;

    }

    public static BufferedImage binaryImage2(BufferedImage bufferedImage) {
        int height = bufferedImage.getHeight();
        int width = bufferedImage.getWidth();
        int rgb = bufferedImage.getRGB(0, 0);
        int arr[][] = new int[width][height];//存放图片每个像素点的灰度值
        //
        for (int i = 0; i < width; i++) {
            for (int j = 0; j < height; j++) {
                arr[i][j] = getImageRgb(bufferedImage.getRGB(i, j));
            }
        }
//        构造一个类型为预定义图像类型之一的 BufferedImage，TYPE_BYTE_BINARY（表示一个不透明的以字节打包的 1、2 或 4 位图像。）
        BufferedImage newBufferedImage = new BufferedImage(width, height, BufferedImage.TYPE_BYTE_BINARY);
        int threshold = 130;//阈值 关于阀值，网上有许多算法，有兴趣的朋友可以自己研究下，这里我随机给出了一个中间数130。
        for (int i = 0; i < width; i++) {
            for (int j = 0; j < height; j++) {
//                大于阀值则设为黑色，小于则为白色
                if (getGray(arr, i, j, width, height) > threshold) {
                    int black = new Color(255, 255, 255).getRGB();
                    newBufferedImage.setRGB(i, j, black);
                } else {
                    int white = new Color(0, 0, 0).getRGB();
                    newBufferedImage.setRGB(i, j, white);
                }
            }
        }
        return newBufferedImage;
//        ImageIO.write(newBufferedImage,"jpg",new File("D:/binaryzation-wuyanzu.jpg"));
        //       System.out.println("图片二值化成功");
//            //下面这段主要是实现加水印的功能 可忽略
//            int fontStyle=1;
//            int fontSize=20;//字体大小
//            File pressFile =new File("D:/QRCodetest/pressText.txt");
//            String pressText = ReadFromFile.readFromFile(pressFile);
//            String newImg="D:"+File.separator+"newPicWithPressText.jpg";
//            String targetImg="D:"+File.separator+"binaryzation"+File.separator+"binaryzation-wuyanzu.jpg";
//            QRCodeUtils.pressText(pressText,newImg,targetImg,fontStyle, Color.green,fontSize,width,height);
    }

    /**
     * //自己加周围8个灰度值再除以9，算出其相对灰度值
     *
     * @param gray
     * @param x
     * @param y
     * @param width
     * @param height
     * @return
     */
    private static int getGray(int[][] gray, int x, int y, int width, int height) {
        int rs = gray[x][y]
                + (x == 0 ? 255 : gray[x - 1][y])
                + (x == 0 || y == 0 ? 255 : gray[x - 1][y - 1])
                + (x == 0 || y == height - 1 ? 255 : gray[x - 1][y + 1])
                + (y == 0 ? 255 : gray[x][y - 1])
                + (y == height - 1 ? 255 : gray[x][y + 1])
                + (x == width - 1 ? 255 : gray[x + 1][y])
                + (x == width - 1 || y == 0 ? 255 : gray[x + 1][y - 1])
                + (x == width - 1 || y == height - 1 ? 255 : gray[x + 1][y + 1]);
        return rs / 9;
    }

    /**
     * 得到图片灰度值
     *
     * @param rgb
     * @return
     */
    private static int getImageRgb(int rgb) {
        //关于图片的灰度值，这里使用简单的(R+G+B)/3
        String argb = Integer.toHexString(rgb);//十进制转十六进制
        int r = Integer.parseInt(argb.substring(2, 4), 16);//16代表16进制
        int g = Integer.parseInt(argb.substring(4, 6), 16);
        int b = Integer.parseInt(argb.substring(6, 8), 16);
        int result = (int) ((r + g + b) / 3);
        return result;
    }

    /**
     * 降噪（领域检测法），针对二值化后的图片来说(白底黑字)，噪点就是图片中一堆密集黑色像素点中少许白色像素点(字体里的白点或背景里的黑点)，这时，解决方法可以遍历像素点，一个像素点周围有8个像素点，如果这个像素点周围有6个以上像素点是黑色就可以把这个像素点也认为是黑色
     *
     * @param image 传入图片
     * @return java.awt.image.BufferedImage
     * @author GUOZHIPENG
     * @date 2021/8/7 18:36
     */
    public static BufferedImage denoise(BufferedImage image) {
        int w = image.getWidth();
        int h = image.getHeight();
        int white = new Color(255, 255, 255).getRGB();

        if (isWhite(image.getRGB(1, 0)) && isWhite(image.getRGB(0, 1)) && isWhite(image.getRGB(1, 1))) {
            image.setRGB(0, 0, white);
        }
        if (isWhite(image.getRGB(w - 2, 0)) && isWhite(image.getRGB(w - 1, 1)) && isWhite(image.getRGB(w - 2, 1))) {
            image.setRGB(w - 1, 0, white);
        }
        if (isWhite(image.getRGB(0, h - 2)) && isWhite(image.getRGB(1, h - 1)) && isWhite(image.getRGB(1, h - 2))) {
            image.setRGB(0, h - 1, white);
        }
        if (isWhite(image.getRGB(w - 2, h - 1)) && isWhite(image.getRGB(w - 1, h - 2)) && isWhite(image.getRGB(w - 2, h - 2))) {
            image.setRGB(w - 1, h - 1, white);
        }

        for (int x = 1; x < w - 1; x++) {
            int y = 0;
            if (isBlack(image.getRGB(x, y))) {
                int size = 0;
                if (isWhite(image.getRGB(x - 1, y))) {
                    size++;
                }
                if (isWhite(image.getRGB(x + 1, y))) {
                    size++;
                }
                if (isWhite(image.getRGB(x, y + 1))) {
                    size++;
                }
                if (isWhite(image.getRGB(x - 1, y + 1))) {
                    size++;
                }
                if (isWhite(image.getRGB(x + 1, y + 1))) {
                    size++;
                }
                if (size >= 5) {
                    image.setRGB(x, y, white);
                }
            }
        }
        for (int x = 1; x < w - 1; x++) {
            int y = h - 1;
            if (isBlack(image.getRGB(x, y))) {
                int size = 0;
                if (isWhite(image.getRGB(x - 1, y))) {
                    size++;
                }
                if (isWhite(image.getRGB(x + 1, y))) {
                    size++;
                }
                if (isWhite(image.getRGB(x, y - 1))) {
                    size++;
                }
                if (isWhite(image.getRGB(x + 1, y - 1))) {
                    size++;
                }
                if (isWhite(image.getRGB(x - 1, y - 1))) {
                    size++;
                }
                if (size >= 5) {
                    image.setRGB(x, y, white);
                }
            }
        }

        for (int y = 1; y < h - 1; y++) {
            int x = 0;
            if (isBlack(image.getRGB(x, y))) {
                int size = 0;
                if (isWhite(image.getRGB(x + 1, y))) {
                    size++;
                }
                if (isWhite(image.getRGB(x, y + 1))) {
                    size++;
                }
                if (isWhite(image.getRGB(x, y - 1))) {
                    size++;
                }
                if (isWhite(image.getRGB(x + 1, y - 1))) {
                    size++;
                }
                if (isWhite(image.getRGB(x + 1, y + 1))) {
                    size++;
                }
                if (size >= 5) {
                    image.setRGB(x, y, white);
                }
            }
        }

        for (int y = 1; y < h - 1; y++) {
            int x = w - 1;
            if (isBlack(image.getRGB(x, y))) {
                int size = 0;
                if (isWhite(image.getRGB(x - 1, y))) {
                    size++;
                }
                if (isWhite(image.getRGB(x, y + 1))) {
                    size++;
                }
                if (isWhite(image.getRGB(x, y - 1))) {
                    size++;
                }
                //斜上下为空时，去掉此点
                if (isWhite(image.getRGB(x - 1, y + 1))) {
                    size++;
                }
                if (isWhite(image.getRGB(x - 1, y - 1))) {
                    size++;
                }
                if (size >= 5) {
                    image.setRGB(x, y, white);
                }
            }
        }

        //降噪，以1个像素点为单位
        for (int y = 1; y < h - 1; y++) {
            for (int x = 1; x < w - 1; x++) {
                if (isBlack(image.getRGB(x, y))) {
                    int size = 0;
                    //上下左右均为空时，去掉此点
                    if (isWhite(image.getRGB(x - 1, y))) {
                        size++;
                    }
                    if (isWhite(image.getRGB(x + 1, y))) {
                        size++;
                    }
                    //上下均为空时，去掉此点
                    if (isWhite(image.getRGB(x, y + 1))) {
                        size++;
                    }
                    if (isWhite(image.getRGB(x, y - 1))) {
                        size++;
                    }
                    //斜上下为空时，去掉此点
                    if (isWhite(image.getRGB(x - 1, y + 1))) {
                        size++;
                    }
                    if (isWhite(image.getRGB(x + 1, y - 1))) {
                        size++;
                    }
                    if (isWhite(image.getRGB(x + 1, y + 1))) {
                        size++;
                    }
                    if (isWhite(image.getRGB(x - 1, y - 1))) {
                        size++;
                    }
                    if (size >= 8) {
                        image.setRGB(x, y, white);
                    }
                }
            }
        }

        return image;
    }

    public static boolean isBlack(int colorInt) {
        Color color = new Color(colorInt);
        if (color.getRed() + color.getGreen() + color.getBlue() <= 300) {
            return true;
        }
        return false;
    }

    public static boolean isWhite(int colorInt) {
        Color color = new Color(colorInt);
        if (color.getRed() + color.getGreen() + color.getBlue() > 300) {
            return true;
        }
        return false;
    }

    public static int isBlack(int colorInt, int whiteThreshold) {
        final Color color = new Color(colorInt);
        if (color.getRed() + color.getGreen() + color.getBlue() <= whiteThreshold) {
            return 1;
        }
        return 0;

    }

    /**
     * 图像类型转换：GIF->JPG、GIF->PNG、PNG->JPG、PNG->GIF(X)、BMP->PNG
     *
     * @param bufferedImage 源图像
     * @param formatName    转换后图片格式
     * @return java.awt.image.BufferedImage 结果图像
     * @author GUOZHIPENG
     * @date 2021/8/7 18:45
     */
    public static BufferedImage convert(BufferedImage bufferedImage, String formatName) {
        try {
            return Thumbnails.of(bufferedImage).outputFormat(formatName).asBufferedImage();
        } catch (IOException e) {
            e.printStackTrace();
        }
        return null;

    }

    /**
     * 旋转图像
     *
     * @param bufferedImage 源图像
     * @param rotate        (角度),正数：顺时针负数：逆时针
     * @return java.awt.image.BufferedImage 结果图像
     * @author GUOZHIPENG
     * @date 2021/8/7 19:12
     */
    public static BufferedImage revolve(BufferedImage bufferedImage, int rotate) {
        try {
            return Thumbnails.of(bufferedImage).rotate(rotate).asBufferedImage();
        } catch (IOException e) {
            e.printStackTrace();
        }
        return null;
    }

    /**
     * 裁剪图片
     *
     * @param bufferedImage 源图像
     * @param x             裁剪起点横坐标
     * @param y             裁剪起点纵坐标
     * @param w             需要裁剪的宽度
     * @param h             需要裁剪的高度
     * @return java.awt.image.BufferedImage 结果图像
     * @author GUOZHIPENG
     * @date 2021/8/7 19:16
     */
    public static BufferedImage getSubImage(BufferedImage bufferedImage, int x, int y, int w, int h) {
        try {
            return Thumbnails.of(bufferedImage).sourceRegion(x, y, w, h).keepAspectRatio(false).asBufferedImage();
        } catch (IOException e) {
            e.printStackTrace();
        }
        return null;
    }

    /**
     * 计算图片文字像素占比
     *
     * @param bufferedImage 源图像
     * @return double 比例值
     * @author GUOZHIPENG
     * @date 2021/8/7 19:22
     */
    public static float getPixelRatio(BufferedImage bufferedImage) {
        int sum = bufferedImage.getHeight() * bufferedImage.getWidth();
        int white = 0;
        for (int i = 0; i < bufferedImage.getWidth(); i++) {
            for (int j = 0; j < bufferedImage.getHeight(); j++) {
                int result = bufferedImage.getRGB(i, j);
                if (isWhite(result)) {
                    white++;
                }

            }
        }
        return 1 - white / sum;
    }

    /**
     * 计算图片黑色像素多少
     *
     * @param bufferedImage 源图像
     * @return double 比例值
     * @author GUOZHIPENG
     * @date 2021/8/7 19:22
     */
    public static float getPixelSize(BufferedImage bufferedImage) {
        int sum = bufferedImage.getHeight() * bufferedImage.getWidth();
        int white = 0;
        for (int i = 0; i < bufferedImage.getWidth(); i++) {
            for (int j = 0; j < bufferedImage.getHeight(); j++) {
                int result = bufferedImage.getRGB(i, j);
                if (isWhite(result)) {
                    white++;
                }

            }
        }
        return sum - white;
    }

    public static BufferedImage multipartFileToBufferedImage(MultipartFile file) {
        BufferedImage f = null;
        try {
            f = ImageIO.read(file.getInputStream());
        } catch (IOException e) {
            e.printStackTrace();
        }
        return f;
    }

    public static File bufferedImageTofile(BufferedImage preImages) {
//        File outputfile = new File();
//        try {
//            ImageIO.write(preImages, "jpg", outputfile);
//        } catch (IOException e) {
//            e.printStackTrace();
//        }
//        return outputfile;
        return null;
    }

    /**
     * @param bufferedImage 切割图片
     * @return java.util.List<java.awt.image.BufferedImage>
     * @author GUOZHIPENG
     * @date 2021/9/12 10:57
     */
    public static List<BufferedImage> CutPicture(BufferedImage bufferedImage) {
        return null;
    }
}
